package cn.tedu.luban.worker.main.service;

import cn.tedu.luban.account.api.AccountApi;
import cn.tedu.luban.account.protocol.dto.AccountDTO;
import cn.tedu.luban.account.protocol.param.AccountCreateParam;
import cn.tedu.luban.attach.api.AttachApi;
import cn.tedu.luban.attach.protocol.dto.AttachDTO;
import cn.tedu.luban.attach.protocol.param.AttachUpdateParam;
import cn.tedu.luban.attach.protocol.query.AttachQuery;
import cn.tedu.luban.passport.protocol.jwt.UserPrinciple;
import cn.tedu.luban.passport.sdk.security.LubanSecurityContext;
import cn.tedu.luban.worker.common.enums.AuditStatusEnum;
import cn.tedu.luban.worker.common.enums.WorkerResultEnum;
import cn.tedu.luban.worker.main.repository.WorkerAreaRepository;
import cn.tedu.luban.worker.main.repository.WorkerAuditLogRepository;
import cn.tedu.luban.worker.main.repository.WorkerCategoryRepository;
import cn.tedu.luban.worker.main.repository.WorkerRepository;
import cn.tedu.luban.worker.protocol.bo.*;
import cn.tedu.luban.worker.protocol.param.AuditSubmitParam;
import cn.tedu.luban.worker.protocol.param.IdCardParam;
import cn.tedu.luban.worker.protocol.param.WorkerParam;
import cn.tedu.luban.worker.protocol.param.WorkerRegistParam;
import cn.tedu.luban.worker.protocol.query.WorkerListQuery;
import com.github.xiaoymin.knife4j.core.util.CollectionUtils;
import com.tedu.inn.protocol.ListRecordTotalBO;
import com.tedu.inn.protocol.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Service
@Slf4j
public class WorkerService {

    @Autowired
    private WorkerRepository workerRepository;

    @Autowired
    private WorkerAuditLogRepository workerAuditLogRepository;

    @DubboReference
    private AttachApi attachApi;

    @DubboReference
    private AccountApi accountApi;
    
    @Transactional(rollbackFor = Exception.class)
    public Long registWorker(WorkerRegistParam workerRegistParam) throws BusinessException {
        //1.补充userId
        Long userId=getUserId();
        workerRegistParam.setUserId(userId);
        //2.验证身份信息参数
        checkIdParam(workerRegistParam);
        //3.写本地数据 新增师傅、新增师傅服务区域、新增师傅服务品类
        Long workerId=saveWorker(workerRegistParam);
        saveWorkerAreas(workerRegistParam);
        saveWorkerCategories(workerRegistParam);
        //4.绑定图片，调用远程接口
        bindPictures(workerRegistParam);
        return workerId;
    }

    private void bindPictures(WorkerRegistParam workerRegistParam) throws BusinessException {
        ArrayList<AttachUpdateParam> attachUpdateParams = new ArrayList<>();
        //1.从入驻的入参中获取上传图片的信息，主要是使用ID
        List<IdCardParam> attachList = workerRegistParam.getAttachList();
        //2.遍历入参，封装PRC接口参数
        for (IdCardParam idCardParam : attachList) {
            AttachUpdateParam attachUpdateParam=new AttachUpdateParam();
            attachUpdateParam.setId(idCardParam.getId());
            attachUpdateParam.setBusinessId(workerRegistParam.getUserId().intValue());
            attachUpdateParam.setBusinessType(100);
            attachUpdateParam.setIsCover(1);
            attachUpdateParams.add(attachUpdateParam);
        }
        int result=attachApi.batchUpdateAttachByIdList(attachUpdateParams);
        if (result==0){
            throw new BusinessException(WorkerResultEnum.ATTACH_UPDATE_FAILED);
        }
    }

    @Autowired
    private WorkerCategoryRepository workerCategoryRepository;

    private void saveWorkerCategories(WorkerRegistParam workerRegistParam) {
        workerCategoryRepository.deleteByUserId(workerRegistParam.getUserId());
        workerCategoryRepository.saveWorkerCategories(workerRegistParam);
    }

    @Autowired
    private WorkerAreaRepository workerAreaRepository;

    private void saveWorkerAreas(WorkerRegistParam workerRegistParam) {
        workerAreaRepository.deleteByUserId(workerRegistParam.getUserId());
        workerAreaRepository.saveWorkerAreas(workerRegistParam);
    }

    private Long saveWorker(WorkerRegistParam workerRegistParam) {
        //考虑幂等问题，用户只对应一位师傅，师傅表只会记录一条数据
        //删除师傅信息
        log.info("workerRegistParam:{}",workerRegistParam);
        workerRepository.deleteByUserId(workerRegistParam.getUserId());
        //执行师傅新增
        return workerRepository.saveWorker(workerRegistParam);
    }

    private void checkIdParam(WorkerRegistParam workerRegistParam) {
        //1.图片号码和提交号码是否一致
        //2.验证身份证号和身份真实姓名是否匹配
        //3.使用api将param里的idCard身份证号，替换中间的9位号码值
    }

    //TODO 获取Http请求中的认证对象ID的值
    private Long getUserId() throws BusinessException {
        UserPrinciple loginToken = LubanSecurityContext.getLoginToken();
        if (loginToken==null)
            throw new BusinessException(WorkerResultEnum.USER_TOKEN_VERIFY_FAILED);
        return loginToken.getId();
    }

    public FrontWorkerBO detailWorker() throws BusinessException {
        //1.获取当前登陆的userId
        Long userId = getUserId();
        //2.根据userId查询对应的师傅数据
        FrontWorkerBO frontWorkerBO=workerRepository.getWorkerByUserId(userId);
        //判断 是否查询出来数据
        if (frontWorkerBO.getUserId()==null){
            frontWorkerBO.setAuditStatus(AuditStatusEnum.UNCREATED.getValue());
        }else {
            //封装当前workerBO的areaList和categoryList
            putAreasAndCategories(frontWorkerBO);
            //判断审核状态 2 1 0
            Integer auditStatus = frontWorkerBO.getAuditStatus();
            if (auditStatus==0) {
                //调用仓储层 workerAuditRepository 查询最后一次驳回信息
                String rejectReason=workerAuditLogRepository.getReason(userId);
                frontWorkerBO.setRejectReason(rejectReason);
            }else if (auditStatus==1){
                //调用RPC查询account余额，totalAmount
                AccountDTO account = accountApi.getAccount(userId);
                if (account!=null){
                    FrontAccountBO frontAccountBO = new FrontAccountBO();
                    frontAccountBO.setTotalAmount(account.getTotalAmount());
                    frontWorkerBO.setFrontAccountBO(frontAccountBO);
                }else {
                    throw new BusinessException("4005","查询账户失败");
                }


            }
        }
        return frontWorkerBO;
    }

    private void putAreasAndCategories(FrontWorkerBO frontWorkerBO) {
        //areaList
        List<WorkerAreaBO> workerAreaBOList=workerAreaRepository.getAreasByUserId(frontWorkerBO.getUserId());
        frontWorkerBO.setWorkerAreaBOList(workerAreaBOList);

        //categoryList
        List<WorkerCategoryBO> categoryBOS=workerCategoryRepository.getCategoriesByUserId(frontWorkerBO.getUserId());
        frontWorkerBO.setWorkerCategoryBOList(categoryBOS);

    }

    public ListRecordTotalBO<AdminWorkerBO> auditListWorkerTotal(WorkerListQuery workerListQuery) throws BusinessException {
        //1.根据入参情况，封装List<Integer> auditSatus
        putAuditStatus(workerListQuery);
        //2.调用仓储层查询满足query条件的师傅的total总数
        ListRecordTotalBO<AdminWorkerBO> bo=null;
        Long total=workerRepository.countWorkerQuery(workerListQuery);
        if (total==0){
            bo=new ListRecordTotalBO<>(null,total);
        }else {
            List<AdminWorkerBO> list=workerRepository.workerPageQuery(workerListQuery);
            putAreasAndCategories(list);
            bo=new ListRecordTotalBO<>(list,total);
        }
        return bo;
    }

    private void putAreasAndCategories(List<AdminWorkerBO> list) throws BusinessException {
        if (CollectionUtils.isNotEmpty(list)){
            for (AdminWorkerBO adminWorkerBO : list) {
                Long userId = adminWorkerBO.getUserId();
                //查询区域
                List<WorkerAreaBO> areaBOS = workerAreaRepository.getAreasByUserId(userId);
                //查询品类
                List<WorkerCategoryBO> categoryBOS = workerCategoryRepository.getCategoriesByUserId(userId);

                List<String> areas = new ArrayList<>();
                for (WorkerAreaBO areaBO : areaBOS) {
                    areas.add(areaBO.getAreaDetail());
                }

                List<String> categories = new ArrayList<>();
                for (WorkerCategoryBO categoryBO : categoryBOS) {
                    categories.add(categoryBO.getCategoryDetail());
                }
                adminWorkerBO.setAreaDetails(areas);
                adminWorkerBO.setCategoryDetails(categories);
            }
        }else {
            throw new BusinessException(WorkerResultEnum.BIND_ERROR);
        }
    }

    private void putAuditStatus(WorkerListQuery workerListQuery) {

        if (CollectionUtils.isEmpty(workerListQuery.getAuditStatus())){
            //封装审核状态0，2
            workerListQuery.setAuditStatus(Arrays.asList(0,2));
        }
    }

    public AdminWorkerBO auditDetail(Long userId) throws BusinessException {
        //1.调用仓储层查询adminWorkerBO对象
        AdminWorkerBO adminWorkerBO=workerRepository.getAdminWorkerByUserId(userId);

        if (adminWorkerBO==null || adminWorkerBO.getId()==null){
            throw new BusinessException(WorkerResultEnum.WORKER_NOT_FOUND);
        }else {
            //可以封装区域和品类
            putAreasAndCategories(adminWorkerBO);
            //根据userId查询审核日志
//            List<AdminAuditBO> auditBOS=new ArrayList<>();
            List<AdminAuditBO> auditBOS=workerAuditLogRepository.getAuditLogs(userId);
            adminWorkerBO.setWorkerAuditLogs(auditBOS);
            //根据业务数据bizType = 100，bizId= userId 查询图片 填补图片
            getAttachUrls(adminWorkerBO);
        }
        return adminWorkerBO;
    }

    private void getAttachUrls(AdminWorkerBO adminWorkerBO) {
        AttachQuery attachQuery = new AttachQuery();
        attachQuery.setBusinessId(adminWorkerBO.getUserId().intValue());
        attachQuery.setBusinessType(100);
        List<AttachDTO> attachDTOS= attachApi.getAttachInfoByParam(attachQuery);

        //封装一个只有url字符串图片地址的list数据，交给workerBO使用
        List<String> urls=new ArrayList<>();
        for (AttachDTO attachDTO : attachDTOS) {
            String fileUuid = attachDTO.getFileUuid();
            String url="http://localhost:8092/static/"+fileUuid;
            urls.add(url);
        }
        adminWorkerBO.setAttachInfo(urls);
    }

    private void putAreasAndCategories(AdminWorkerBO adminWorkerBO) throws BusinessException {
        ArrayList<AdminWorkerBO> adminWorkerBOS = new ArrayList<>();
        adminWorkerBOS.add(adminWorkerBO);
        putAreasAndCategories(adminWorkerBOS);
    }

    public Long auditSumbit(AuditSubmitParam auditSubmitParam) throws BusinessException {
        //param 填补userId
        auditSubmitParam.setUserId(auditSubmitParam.getWorkerId());
        //1.利用userId查询当前的师傅信息
        AdminWorkerBO adminWorkerBO = workerRepository.getAdminWorkerByUserId(auditSubmitParam.getUserId());
        //判断是否有值
        if (adminWorkerBO==null || adminWorkerBO.getId()==null){
            throw new BusinessException(WorkerResultEnum.WORKER_NOT_FOUND);
        }
        //判断状态流转，获取当前审核状态
        Integer currentAuditStatus = adminWorkerBO.getAuditStatus();
        //判断currentAuditStatus ==1
        if (currentAuditStatus==1) {
            throw new BusinessException(WorkerResultEnum.AUDIT_STATUS_TRANSFER_ERROR);
        }

        Long auditId=workerAuditLogRepository.saveWorkerAudit(auditSubmitParam);

        //修改师傅审核状态
        WorkerParam workerParam = new WorkerParam();
        workerParam.setAuditStatus(auditSubmitParam.getAuditStatus());
        workerParam.setUserId(auditSubmitParam.getUserId());
        workerRepository.updateAuditStatus(workerParam);

        //判断师傅是否需要创建账户
        if (auditSubmitParam.getAuditStatus()==1 && adminWorkerBO.getCertStatus()==0){
            //满足了给师傅创建账户的情况
            // 修改师傅的certStatus 1
            workerParam.setCertStatus(1);
            workerParam.setId(adminWorkerBO.getId());
            workerRepository.updateCertStatus(workerParam);
            //远程调用account创建 一个该师傅的绑定账户
            AccountCreateParam accountCreateParam = new AccountCreateParam();
            accountCreateParam.setUserId(workerParam.getUserId());
            accountCreateParam.setUserName(adminWorkerBO.getRealName());
            accountCreateParam.setUserPhone(adminWorkerBO.getPhone());
            accountApi.createAccount(accountCreateParam);

        }

        return auditId;


    }
}
